package com.utc.cards.player.jade.agent.playerAgent;

import jade.core.behaviours.CyclicBehaviour;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;

import java.util.ArrayList;
import java.util.Map.Entry;
import java.util.StringTokenizer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.utc.cards.common.jade.Mapper;
import com.utc.cards.model.Scores;
import com.utc.cards.model.deck.Deck;
import com.utc.cards.model.game.Info;
import com.utc.cards.model.player.Hands;
import com.utc.cards.model.player.HumanPlayer;
import com.utc.cards.model.player.IPlayer;

public class PlayerListenerBehaviour extends CyclicBehaviour
{

    private static final String CONVERSATION_ID = "info";
    private static final long serialVersionUID = 5312576538932622504L;
    private static Logger log = LoggerFactory.getLogger(PlayerListenerBehaviour.class);

    private PlayerAgent agent;

    public PlayerListenerBehaviour(PlayerAgent playerAgent)
    {
        super(playerAgent);
        this.agent = playerAgent;
    }

    private MessageTemplate template = MessageTemplate.MatchConversationId(CONVERSATION_ID);

    public void action()
    {
        ACLMessage msg = agent.receive(template);
        if (msg != null)
        {
            if (msg.getPerformative() == ACLMessage.INFORM)
            {
                Info info = null;
                try
                {
                    info = Mapper.getObjectMapper().readValue(msg.getContent(), Info.class);
                }
                catch (Exception e)
                {
                    log.error("Error while mapping String to Info");
                    e.printStackTrace();
                }
                log.debug("{} received a message {}", agent.getLocalName(), info.getType());
                switch (info.getType())
                {
                case INFO:
                {
                    log.debug("INFO");
                    agent.notifyInfo(info.getJson());
                    break;
                }
                case PLAYERS_LIST:
                {
                    log.debug("PLAYERS_LIST:" + info.getJson());
                    if (info.getJson().contains("|"))
                    {
                        StringTokenizer st = new StringTokenizer(info.getJson());

                        ArrayList<String> players = new ArrayList<String>();

                        while (st.hasMoreTokens())
                        {
                            String s = st.nextToken("|");
                            players.add(s);
                        }

                        String[] tmp = new String[players.size()];

                        tmp = (String[]) players.toArray(tmp);

                        agent.notifyPlayersChanged(tmp);
                    }
                    else
                    {
                        String players[] =
                        { info.getJson() };
                        agent.notifyPlayersChanged(players);
                    }
                    break;
                }
                case PLAYER_TURN:
                {
                    log.debug("PLAYER_TURN");
                    agent.onPlayerTurn();
                    break;
                }
                case GAME_SELECTION:
                {
                    log.debug("GAME_SELECTION");
                    agent.onGameSelection(info.getJson());
                    break;
                }
                case GAME_START:
                {
                    log.debug("GAME_START");
                    agent.onGameStart();
                    break;
                }
                case GAME_END:
                {
                    log.debug("GAME_END");
                    agent.onGameEnd();
                    break;
                }
                case SCORE:
                {
                    log.debug("SCORE");
                    try
                    {
                        Scores scores = Mapper.getObjectMapper().readValue(msg.getContent(), Scores.class);
                        agent.getModel().setScores(scores);
                        agent.onScoreReception();
                    }
                    catch (Exception e)
                    {
                        log.error("Error while mapping String to Scores");
                        e.printStackTrace();
                    }
                    break;
                }
                case SET_CARDS:
                {
                    log.debug("SET_CARDS");

                    {
                        Hands hands = null;
                        try
                        {
                            hands = Mapper.getObjectMapper().readValue(info.getJson(), Hands.class);

                            log.debug("SET_CARDS " + hands);
                            agent.getModel().getPlayer().setHands(hands.getHands());
                            log.debug("SET_CARDS new hands" + agent.getModel().getPlayer().getHand());

                            if (agent.getModel().getPlayer() instanceof HumanPlayer)
                            {
                                agent.onCardsChanged(hands, info.getType());
                            }
                        }
                        catch (Exception e)
                        {
                            e.printStackTrace();
                        }

                    }
                    break;
                }
                case CLEAR_CARDS:
                {
                    log.debug("CLEAR_CARDS");
                    {
                        agent.getModel().getPlayer().getHands().clear();
                        agent.getModel().getPlayer().setHand(new Deck(), IPlayer.MAIN_HAND);

                        if (agent.getModel().getPlayer() instanceof HumanPlayer)
                        {
                            agent.onCardsChanged(null, info.getType());
                        }
                    }
                    break;
                }
                case ADD_CARDS:
                {
                    log.debug("ADD_CARDS");
                    {
                        Hands hands = null;
                        try
                        {
                            hands = Mapper.getObjectMapper().readValue(info.getJson(), Hands.class);

                            for (Entry<String, Deck> entry : hands.getHands().entrySet())
                            {
                                Deck deck;
                                deck = agent.getModel().getPlayer().getHand(entry.getKey());
                                deck.addAll(entry.getValue());
                                agent.getModel().getPlayer().setHand(entry.getValue(), entry.getKey());
                            }

                            if (agent.getModel().getPlayer() instanceof HumanPlayer)
                            {
                                agent.onCardsChanged(hands, info.getType());
                            }
                        }
                        catch (Exception e)
                        {
                            e.printStackTrace();
                        }
                    }
                    break;
                }
                case REMOVE_CARDS:
                {
                    log.debug("REMOVE_CARDS");
                    {
                        Hands hands = extractHands(info.getJson());
                        for (Entry<String, Deck> entry : hands.getHands().entrySet())
                        {
                            agent.getModel().getPlayer().getHand(entry.getKey()).removeAll(entry.getValue());
                        }

                        if (agent.getModel().getPlayer() instanceof HumanPlayer)
                        {
                            agent.onCardsChanged(hands, info.getType());
                        }
                    }
                    break;
                }
                default:
                    log.error("TYPE D'INFO NON GERE");
                    break;
                }
            }
        }
        block();
    }

    private Hands extractHands(String string)
    {
        try
        {
            log.debug("extractHands" + string);
            Hands result = Mapper.getObjectMapper().readValue(string, Hands.class);
            return result;
        }
        catch (Exception e)
        {
            log.error("Error while mapping String to Hands");
            e.printStackTrace();
            return null;
        }

    }
}
